using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Surface;
using Microsoft.Surface.Core;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace SurfaceArtillery
{
    /// <summary>
    /// This is the main type for your application.
    /// </summary>
    public class App1 : Microsoft.Xna.Framework.Game
    {
        private readonly GraphicsDeviceManager graphics;
        private ContactTarget contactTarget;
        private Color backgroundColor = new Color(0, 0, 0);
        private bool applicationLoadCompleteSignalled;

        private UserOrientation currentOrientation = UserOrientation.Bottom;
        private Matrix screenTransform = Matrix.Identity;
        private Matrix inverted;

        // application state: Activated, Previewed, Deactivated,
        // start in Activated state
        private bool isApplicationActivated = true;
        private bool isApplicationPreviewed;

        private SpriteBatch artillerySprite;
        private Texture2D background;
        private Texture2D planet1;
        private Texture2D planet2;
        private Texture2D sun;
        private Texture2D moon;
        private Texture2D mars;
        private Texture2D rocket1;
        private Texture2D rocket2;
        private Texture2D arrow;
        private Texture2D button;
        private SpriteFont font;

        private int state = 1;
        private int level = 1;
        private int player1Points = 0;
        private int player2Points = 0;

        private int player1Pop;
        private int player2Pop;

        private int player1Aimer = 0;
        private int player2Aimer = 0;
        private int player1Weighter = 0;
        private int player2Weighter = 0;

        private float maxPower = 10;
        private int playerTurn = 1;
        private int startingPop = 1000000;
        private int tagRotationDetail = 200;

        Random rand = new Random();

        private Vector2 player1PlanetPosition = new Vector2(100, 568);
        private Vector2 player2PlanetPosition = new Vector2(924, 200);

        private ReadOnlyContactCollection oldContacts = null;
        private List<Orb> orbs = new List<Orb>();
        private List<Missile> missiles = new List<Missile>();
        private Missile player1MissileData = new Missile(Vector2.Zero, 1, 1f, Vector2.Zero, (float)Math.PI/2);
        private Missile player2MissileData = new Missile(Vector2.Zero, 1, 1f, Vector2.Zero, -(float)Math.PI / 2);
        private Missile player1LastMissileData = new Missile(Vector2.Zero, 0, 0f, Vector2.Zero, 0);
        private Missile player2LastMissileData = new Missile(Vector2.Zero, 0, 0f, Vector2.Zero, 0);
        
        /// <summary>
        /// The graphics device manager for the application.
        /// </summary>
        protected GraphicsDeviceManager Graphics
        {
            get { return graphics; }
        }

        /// <summary>
        /// The target receiving all surface input for the application.
        /// </summary>
        protected ContactTarget ContactTarget
        {
            get { return contactTarget; }
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public App1()
        {
            graphics = new GraphicsDeviceManager(this);
        }

        #region Initialization

        /// <summary>
        /// Moves and sizes the window to cover the input surface.
        /// </summary>
        private void SetWindowOnSurface()
        {
            System.Diagnostics.Debug.Assert(Window.Handle != System.IntPtr.Zero,
                "Window initialization must be complete before SetWindowOnSurface is called");
            if (Window.Handle == System.IntPtr.Zero)
                return;

            // We don't want to run in full-screen mode because we need
            // overlapped windows, so instead run in windowed mode
            // and resize to take up the whole surface with no border.

            // Make sure the graphics device has the correct back buffer size.
            InteractiveSurface interactiveSurface = InteractiveSurface.DefaultInteractiveSurface;
            if (interactiveSurface != null)
            {
                graphics.PreferredBackBufferWidth = interactiveSurface.Width;
                graphics.PreferredBackBufferHeight = interactiveSurface.Height;
                graphics.ApplyChanges();

                // Remove the border and position the window.
                Program.RemoveBorder(Window.Handle);
                Program.PositionWindow(Window);
            }
        }

        /// <summary>
        /// Initializes the surface input system. This should be called after any window
        /// initialization is done, and should only be called once.
        /// </summary>
        private void InitializeSurfaceInput()
        {
            System.Diagnostics.Debug.Assert(Window.Handle != System.IntPtr.Zero,
                "Window initialization must be complete before InitializeSurfaceInput is called");
            if (Window.Handle == System.IntPtr.Zero)
                return;
            System.Diagnostics.Debug.Assert(contactTarget == null,
                "Surface input already initialized");
            if (contactTarget != null)
                return;

            // Create a target for surface input.
            contactTarget = new ContactTarget(Window.Handle, EventThreadChoice.OnBackgroundThread);
            contactTarget.EnableInput();
        }

        /// <summary>
        /// Reset the application's orientation and transform based on the current launcher orientation.
        /// </summary>
        private void ResetOrientation()
        {
            UserOrientation newOrientation = ApplicationLauncher.Orientation;

            if (newOrientation == currentOrientation) { return; }

            currentOrientation = newOrientation;

            if (currentOrientation == UserOrientation.Top)
            {
                screenTransform = inverted;
            }
            else
            {
                screenTransform = Matrix.Identity;
            }
        }

        #endregion

        #region Helper Methods

        // Calculate starting velocity on a missile and add it to the game
        private void Shoot(Vector2 from, Missile missile)
        {
            Vector2 velocity = new Vector2((float)(Math.Cos((double)missile.Rotation - Math.PI / 2)), (float)(Math.Sin((double)missile.Rotation - Math.PI / 2)));
            velocity = Vector2.Normalize(velocity);
            Vector2 temp = velocity * planet1.Width / 2;
            missiles.Add(new Missile(from+temp, missile.Weight, missile.Power, velocity * (float)Math.Sqrt((2 * missile.Power)/missile.Weight), missile.Rotation, missile.Texture));
        }


        private void UpdateMissiles(GameTime gameTime)
        {
            foreach (Missile missile in missiles)
            {
                Vector2 temp = Vector2.Zero;
                foreach (Orb orb in orbs)
                {
                    float newton = 0.1f * (float)((missile.Weight * orb.Weight) / Math.Pow(Vector2.Distance(missile.Location, orb.Location), 2));
                    missile.Force = orb.Location - missile.Location;
                    if (missile.Force.Length() < orb.Texture.Width / 2)
                    {
                        missile.FlaggedForDeletion = true;
                        break;
                    }
                    missile.Force = Vector2.Normalize(missile.Force) * (float)newton;
                    temp+= missile.Force;
                }
                missile.Velocity += temp;
                missile.Location += missile.Velocity;

                // If a player planet is hit the pop is decreased
                if (Vector2.Distance(missile.Location, player1PlanetPosition) < planet1.Width / 2)
                {
                    missile.FlaggedForDeletion = true;
                    player1Pop -= missile.Damage;
                    CheckPop();
                    break;
                }
                else if (Vector2.Distance(missile.Location, player2PlanetPosition) < planet2.Width / 2)
                {
                    missile.FlaggedForDeletion = true;
                    player2Pop -= missile.Damage;
                    CheckPop();
                    break;
                }

            }
            missiles.RemoveAll(item => item.FlaggedForDeletion);
        }

        // If any population is at zero you die!
        private void CheckPop()
        {
            if (player1Pop < 1)
            {
                player2Points++;
                NewLevel();
            }
            else if (player2Pop < 1)
            {
                player1Points++;
                NewLevel();
            }
        }

        // Remove, generate and fix things for a new level
        private void NewLevel()
        {
            orbs.Clear();
            missiles.Clear();

            player1Pop = startingPop;
            player2Pop = startingPop;

            for (int i = 0; i < level; i++)
            {
                if (i>0)
                    orbs.Add(new Orb(new Vector2(rand.Next(200, 800), rand.Next(70, 700)), 1000, moon, null));
                else
                    orbs.Add(new Orb(new Vector2(rand.Next(200, 800), rand.Next(70, 700)), 10000, sun, null));
            }
            level++;
        }

        private float RotateTag(float to, float from)
        {
            return Math.Abs(to - from) < 2 ? ((float)Math.Sign(to - from)) / tagRotationDetail : 0;
        }
        
        #endregion

        #region Overridden Game Methods

        /// <summary>
        /// Allows the app to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            SetWindowOnSurface();
            InitializeSurfaceInput();

            // Set the application's orientation based on the current launcher orientation
            currentOrientation = ApplicationLauncher.Orientation;

            // Subscribe to surface application activation events
            ApplicationLauncher.ApplicationActivated += OnApplicationActivated;
            ApplicationLauncher.ApplicationPreviewed += OnApplicationPreviewed;
            ApplicationLauncher.ApplicationDeactivated += OnApplicationDeactivated;

            // Setup the UI to transform if the UI is rotated.
            // Create a rotation matrix to orient the screen so it is viewed correctly
            // when the user orientation is 180 degress different.
            inverted = Matrix.CreateRotationZ(MathHelper.ToRadians(180)) *
                       Matrix.CreateTranslation(graphics.GraphicsDevice.Viewport.Width,
                                                 graphics.GraphicsDevice.Viewport.Height,
                                                 0);

            if (currentOrientation == UserOrientation.Top)
            {
                screenTransform = inverted;
            }

            base.Initialize();
        }

        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent()
        {
            // TODO: Load any content

            artillerySprite = new SpriteBatch(GraphicsDevice);
            background = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\bg1.png");
            planet1 = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\planet1.png");
            planet2 = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\planet2.png");
            sun = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\sun.png");
            moon = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\moon.png");
            mars = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\mars.png");
            rocket1 = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\rocket1.png");
            rocket2 = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\rocket2.png");
            arrow = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\arrow.png");
            button = Texture2D.FromFile(graphics.GraphicsDevice, @"Resources\button.png");
            font = Content.Load<SpriteFont>(@"Resources\SpriteFont1");
            player1MissileData.Texture = rocket1;
            player2MissileData.Texture = rocket2;

            NewLevel();
        }

        /// <summary>
        /// Unload your graphics content.
        /// </summary>
        protected override void UnloadContent()
        {
            Content.Unload();
        }

        /// <summary>
        /// Allows the app to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (isApplicationActivated || isApplicationPreviewed)
            {
                if (isApplicationActivated)
                {
                    // TODO: Process contacts, 

                    ReadOnlyContactCollection contacts = contactTarget.GetState();
                    foreach (Contact contact in contacts)
                    {
                        if (oldContacts != null)
                        {
                            if (contact.IsTagRecognized)
                            {
                                if (oldContacts.Contains(contact.Id))
                                {
                                    //player1 button positions
                                    if (contact.CenterX < 150)
                                    {
                                        if (contact.CenterY > 0 && contact.CenterY <= 125)
                                        {//p
                                            player1MissileData.Power += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                            if (player1MissileData.Power > maxPower)
                                                player1MissileData.Power = maxPower;
                                        }
                                        else if (contact.CenterY > 125 && contact.CenterY <= 256)
                                        {//a
                                            player1MissileData.Rotation += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                        }
                                        else if (contact.CenterY > 256 && contact.CenterY <= 380)
                                        {//w
                                            player1MissileData.Weight += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                        }
                                    }
                                    //player2
                                    else if (contact.CenterX > 869)
                                    {
                                        if (contact.CenterY > 380 && contact.CenterY <= 510)
                                        {//w
                                            player2MissileData.Weight += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                        }
                                        else if (contact.CenterY > 510 && contact.CenterY <= 640)
                                        {//a
                                            player2MissileData.Rotation += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                        }
                                        else if (contact.CenterY > 640 && contact.CenterY <= 768)
                                        {//p
                                            player2MissileData.Power += RotateTag(contact.Orientation, oldContacts.GetContactFromId(contact.Id).Orientation);
                                            if (player2MissileData.Power > maxPower)
                                                player2MissileData.Power = maxPower;
                                        }
                                    }
                                    // Player added planets.
                                    else
                                    {
                                        bool exists = false;
                                        foreach (Orb orb in orbs)
                                            if (orb.Tag.HasValue && contact.Tag.Byte.Equals(orb.Tag.Value))
                                                exists = true;
                                        if (!exists)
                                                orbs.Add(new Orb(new Vector2(contact.CenterX, contact.CenterY), 4000, mars, contact.Tag.Byte));
                                    }
                                }
                            }
                            // Fingers
                            else if (contact.IsFingerRecognized)
                            {

                                // Arrow aiming
                                Vector2 aimer;
                                if (contacts.Contains(player1Aimer))
                                {
                                    aimer = new Vector2(contacts.GetContactFromId(player1Aimer).CenterX, contacts.GetContactFromId(player1Aimer).CenterY) - player1PlanetPosition;
                                    player1MissileData.Power = aimer.Length() / planet1.Width * 1.2f;
                                    if (player1MissileData.Power > maxPower)
                                        player1MissileData.Power = maxPower;
                                    player1MissileData.Rotation = (float)(Math.Atan2(aimer.Y, aimer.X) + Math.PI/2);
                                }
                                if (contacts.Contains(player2Aimer))
                                {
                                    aimer = new Vector2(contacts.GetContactFromId(player2Aimer).CenterX, contacts.GetContactFromId(player2Aimer).CenterY) - player2PlanetPosition;
                                    player2MissileData.Power = aimer.Length() / planet2.Width * 1.2f;
                                    if (player2MissileData.Power > maxPower)
                                        player2MissileData.Power = maxPower;
                                    player2MissileData.Rotation = (float)(Math.Atan2(aimer.Y, aimer.X) + Math.PI / 2);
                                }
                                if (contacts.Contains(player1Weighter))
                                {
                                    aimer = new Vector2(contacts.GetContactFromId(player1Weighter).CenterX, contacts.GetContactFromId(player1Weighter).CenterY) - player1PlanetPosition;
                                    player1MissileData.Weight = aimer.Length() / 60;
                                }
                                if (contacts.Contains(player2Weighter))
                                {
                                    aimer = new Vector2(contacts.GetContactFromId(player2Weighter).CenterX, contacts.GetContactFromId(player2Weighter).CenterY) - player2PlanetPosition;
                                    player2MissileData.Weight = aimer.Length() / 60;
                                }

                                // Newly added fingers
                                if (!oldContacts.Contains(contact.Id))
                                {
                                    if (Vector2.Distance(new Vector2(contact.CenterX, contact.CenterY), player1PlanetPosition) < planet1.Width / 2)
                                    {
                                        if  (!contacts.Contains(player1Aimer))
                                            player1Aimer = contact.Id;
                                        else if (!contacts.Contains(player1Weighter))
                                            player1Weighter = contact.Id;
                                    }
                                    else if (Vector2.Distance(new Vector2(contact.CenterX, contact.CenterY), player2PlanetPosition) < planet2.Width / 2)
                                    {
                                        if (!contacts.Contains(player2Aimer))
                                            player2Aimer = contact.Id;
                                        else if (!contacts.Contains(player2Weighter))
                                            player2Weighter = contact.Id;
                                    }

                                    if (playerTurn == 1)
                                    {
                                        if (contact.CenterX <= 120 && contact.CenterY > 654 && player1MissileData.Weight > 0 && player1MissileData.Power > 0)
                                        {
                                            Shoot(player1PlanetPosition, player1MissileData);
                                            playerTurn = 2;
                                            player1LastMissileData = new Missile(Vector2.Zero, player1MissileData.Weight, player1MissileData.Power, Vector2.Zero, player1MissileData.Rotation, rocket1);
                                            player1Pop -= player1MissileData.Cost;
                                            CheckPop();
                                        }
                                    }
                                    else if (playerTurn == 2)
                                    {
                                        if (contact.CenterX > 904 && contact.CenterY <= 120 && player2MissileData.Weight > 0 && player2MissileData.Power > 0)
                                        {
                                            Shoot(player2PlanetPosition, player2MissileData);
                                            playerTurn = 1;
                                            player2LastMissileData = new Missile(Vector2.Zero, player2MissileData.Weight, player2MissileData.Power, Vector2.Zero, player2MissileData.Rotation, rocket2);
                                            player2Pop -= player2MissileData.Cost;
                                            CheckPop();
                                        }
                                    }
                                }
                            }
                        }
                    }

                    UpdateMissiles(gameTime);
                    oldContacts = contacts;
                }

                // TODO: Add your update logic here
            }
            else
            {
                Exit();
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the app should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            if (!applicationLoadCompleteSignalled)
            {
                // Dismiss the loading screen now that we are starting to draw
                ApplicationLauncher.SignalApplicationLoadComplete();
                applicationLoadCompleteSignalled = true;
            }

            //TODO: Rotate the UI based on the value of screenTransform here if desired

            graphics.GraphicsDevice.Clear(backgroundColor);

            //TODO: Add your drawing code here
            //TODO: Avoid any expensive logic if application is neither active nor previewed
            artillerySprite.Begin();

            artillerySprite.Draw(background, Vector2.Zero, null, Color.White, 0, Vector2.Zero, new Vector2(1F, 1F), SpriteEffects.None, 0f);

            // Draw arrows for last missiles.
            artillerySprite.Draw(arrow, player1PlanetPosition, null, new Color(20, 20, 20), player1LastMissileData.Rotation, new Vector2(arrow.Width / 2, arrow.Height), new Vector2(player1LastMissileData.Weight, player1LastMissileData.Power), SpriteEffects.None, 0f);
            artillerySprite.Draw(arrow, player2PlanetPosition, null, new Color(20, 20, 20), player2LastMissileData.Rotation, new Vector2(arrow.Width / 2, arrow.Height), new Vector2(player2LastMissileData.Weight, player2LastMissileData.Power), SpriteEffects.None, 0f);

            // Draw arrows for next missiles.
            artillerySprite.Draw(arrow, player1PlanetPosition, null, Color.White, player1MissileData.Rotation, new Vector2(arrow.Width / 2, arrow.Height), new Vector2(player1MissileData.Weight, player1MissileData.Power), SpriteEffects.None, 0f);
            artillerySprite.Draw(arrow, player2PlanetPosition, null, Color.White, player2MissileData.Rotation, new Vector2(arrow.Width / 2, arrow.Height), new Vector2(player2MissileData.Weight, player2MissileData.Power), SpriteEffects.None, 0f);
            
            artillerySprite.Draw(planet1, player1PlanetPosition, null, Color.White, 0, new Vector2(planet1.Width / 2, planet1.Height / 2), new Vector2(1F, 1F), SpriteEffects.None, 0f);
            artillerySprite.Draw(planet2, player2PlanetPosition, null, Color.White, 0, new Vector2(planet2.Width / 2, planet2.Height / 2), new Vector2(1F, 1F), SpriteEffects.None, 0f);

            foreach (Orb orb in orbs)
            {
                artillerySprite.Draw(orb.Texture, orb.Location, null, Color.White,0f /*(float)(Math.PI * rand.NextDouble())*/, new Vector2(orb.Texture.Width / 2, orb.Texture.Height / 2), 1f, SpriteEffects.None, 0f);
            }
            foreach (Missile missile in missiles)
            {
                artillerySprite.Draw(missile.Texture, missile.Location, null, Color.White, (float)(Math.Atan2(missile.Velocity.Y, missile.Velocity.X)+Math.PI/2), new Vector2(rocket1.Width / 2, rocket1.Height / 2), 1f, SpriteEffects.None, 0f);
            }
            if (playerTurn == 1)
                artillerySprite.Draw(button, new Vector2(125,640), null, Color.White, (float)Math.PI/2, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            else
                artillerySprite.Draw(button, new Vector2(895,125), null, Color.White, -(float)Math.PI / 2, Vector2.Zero, 1f, SpriteEffects.None, 0f);

            String statusTextP1 = "Points: " + player1Points + " Population: " + player1Pop;
            String statusTextP2 = "Points: " + player2Points + " Population: " + player2Pop;
            String missileTextP1 = "Missile:\nPower: " + Math.Round(player1MissileData.Power, 3) + "\nAngle: " + Math.Round(MathHelper.ToDegrees(player1MissileData.Rotation),2) + "\nWeight: " + Math.Round(player1MissileData.Weight, 3) +
                "\nKills: " + player1MissileData.Damage + "\nCosts: " + player1MissileData.Cost;
            String missileTextP2 = "Missile:\nPower: " + Math.Round(player2MissileData.Power, 3) + "\nAngle: " +  Math.Round(MathHelper.ToDegrees(player2MissileData.Rotation),2) + "\nWeight: " + Math.Round(player2MissileData.Weight, 3) +
                "\nKills: " + player2MissileData.Damage + "\nCosts: " + player2MissileData.Cost;

            artillerySprite.DrawString(font, statusTextP1, new Vector2(170, 154), Color.White, (float)Math.PI / 2, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            artillerySprite.DrawString(font, missileTextP1, new Vector2(140, 390), Color.White, (float)Math.PI / 2, Vector2.Zero, 1f, SpriteEffects.None, 0f);

            artillerySprite.DrawString(font, statusTextP2, new Vector2(852, 604), Color.White, -(float)Math.PI / 2, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            artillerySprite.DrawString(font, missileTextP2, new Vector2(880, 375), Color.White, -(float)Math.PI / 2, Vector2.Zero, 1f, SpriteEffects.None, 0f);

            artillerySprite.End();

            base.Draw(gameTime);
        }

        #endregion

        #region Application Event Handlers

        /// <summary>
        /// This is called when application has been activated.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationActivated(object sender, EventArgs e)
        {
            // Update application state.
            isApplicationActivated = true;
            isApplicationPreviewed = false;

            // Orientaton can change between activations.
            ResetOrientation();

            //TODO: Enable audio, animations here

            //TODO: Optionally enable raw image here
        }

        /// <summary>
        /// This is called when application is in preview mode.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationPreviewed(object sender, EventArgs e)
        {
            // Update application state.
            isApplicationActivated = false;
            isApplicationPreviewed = true;

            //TODO: Disable audio here if it is enabled

            //TODO: Optionally enable animations here
        }

        /// <summary>
        ///  This is called when application has been deactivated.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationDeactivated(object sender, EventArgs e)
        {
            // Update application state.
            isApplicationActivated = false;
            isApplicationPreviewed = false;

            //TODO: Disable audio, animations here

            //TODO: Disable raw image if it's enabled
        }

        #endregion

        #region IDisposable

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Release managed resources.
                IDisposable graphicsDispose = graphics as IDisposable;
                if (graphicsDispose != null)
                {
                    graphicsDispose.Dispose();
                }
                if (contactTarget != null)
                {
                    contactTarget.Dispose();
                    contactTarget = null;
                }
            }

            // Release unmanaged Resources.

            // Set large objects to null to facilitate garbage collection.

            base.Dispose(disposing);
        }


        #endregion

    }
}
